﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xaml;
using Microsoft.VisualStudio.Modeling;
using VsxFactory.Modeling.VisualStudio;
using VsxFactory.Modeling.Strategies.Rules;

namespace VsxFactory.Modeling.Strategies
{
    /// <summary>
    /// Stratégie persistable dans un fichier xaml dont l'extension est .mxrules et qui porte le même nom que le modéle.
    /// </summary>
    [VsxFactory.Modeling.Strategies.Strategy("Xml file rules strategy")]
    [System.Windows.Markup.ContentProperty("InnerStrategy")]
    public class XmlRulesStrategy : VsxFactory.Modeling.Strategies.IGenerationStrategy
    {
        private const string Extension = ".mxrules";
        private IVsProject projectNode;
        public Func<VsxFactory.Modeling.Strategies.IStrategyContext, ModelElement, GenerationSpec> CreateGenerationSpec { get; set; }

        public VsxFactory.Modeling.Strategies.IGenerationStrategy InnerStrategy { get; set; }

        public XmlRulesStrategy() {
        }

        // Recherche si il existe dans le projet (sinon ds la solution) si il existe un fichier de règles (.mxrules) qui porte le même nom que le modéle
        bool VsxFactory.Modeling.Strategies.IGenerationStrategy.Initialize(VsxFactory.Modeling.Strategies.IStrategiesHost host, IServiceProvider serviceProvider, IVsProjectFileItem node) {
            string rulesFileName = node.Name + Extension;
            // Recherche des règles dans le projet contenant le modéle
            var ruleNode = node.Solution.Find<IVsProjectFileItem>(pi => String.Compare(pi.Name, rulesFileName, StringComparison.OrdinalIgnoreCase) == 0);
            if (ruleNode != null) {
                var fileName = ruleNode.Path;
                try {
                    using (var stream = new FileStream(fileName, FileMode.Open)) {
                        InnerStrategy = XamlServices.Load(stream) as VsxFactory.Modeling.Strategies.IGenerationStrategy;
                    }
                    projectNode = node.Project;
                    if (CreateGenerationSpec == null)
                        CreateGenerationSpec = (ctx, mel) => new GenerationSpec(mel, projectNode, Guid.Empty);
                    return InnerStrategy.Initialize(host, serviceProvider, node);
                }
                catch (Exception ex) {
                    var ctx = host.GetStrategyContext(this, node, VsxFactory.Modeling.Strategies.CodeGenerationEvent.None);
                    ctx.WriteError("Incorrect rules file {0}. Error when reading rules - {1})", rulesFileName, ex.Message);
                }
            }
            return false;
        }

        void VsxFactory.Modeling.Strategies.IGenerationStrategy.OnDocumentSaved(VsxFactory.Modeling.VisualStudio.IVsProjectFileItem document) {
            InnerStrategy.OnDocumentSaved(document);
        }

        bool VsxFactory.Modeling.Strategies.IGenerationStrategy.OnDocumentClosed(VsxFactory.Modeling.VisualStudio.IVsProjectFileItem document) {
            return InnerStrategy.OnDocumentClosed(document);
        }

        void VsxFactory.Modeling.Strategies.IGenerationStrategy.GenerateArtifacts(VsxFactory.Modeling.VisualStudio.IVsProjectFileItem document) {
            InnerStrategy.GenerateArtifacts(document);
        }
    }
}
